package com.tbb.app.base.service.impl;

import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.tbb.app.base.dto.UserAddDTO;
import com.tbb.app.base.dto.UserCurUpdateDTO;
import com.tbb.app.base.dto.UserPasswordDTO;
import com.tbb.app.base.dto.UserUpdateDTO;
import com.tbb.app.base.entity.User;
import com.tbb.app.base.mapper.UserMapper;
import com.tbb.app.base.search.UserPageSearch;
import com.tbb.app.base.service.IFollowService;
import com.tbb.app.base.service.IUserNoteService;
import com.tbb.app.base.service.IUserService;
import com.tbb.app.base.vo.UserVO;
import com.tbb.app.common.entity.UserInfo;
import com.tbb.app.common.exception.BusinessException;
import com.tbb.app.common.service.CacheService;
import com.tbb.app.common.service.CurrentLoginUserService;
import com.tbb.app.common.service.TokenService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import org.springframework.util.DigestUtils;
import org.springframework.util.StringUtils;

import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Date;
import java.util.List;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

/**
 * 用户表 服务实现类
 *
 * @author Liu
 * @since 2022-01-11
 */
@Service
public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements IUserService {

    @Autowired
    private TokenService tokenService;
    @Autowired
    private CurrentLoginUserService currentLoginUserService;
    @Autowired
    private CacheService cacheService;
    @Autowired
    private IFollowService iFollowService;
    @Autowired
    private IUserNoteService iUserNoteService;

    @Override
    public String login(String account, String password) {
        String md5 = DigestUtils.md5DigestAsHex(password.getBytes(StandardCharsets.UTF_8));
        QueryWrapper<User> wrapper = new QueryWrapper<>();
        wrapper.lambda().eq(User::getAccount, account)
                .eq(User::getPassword, md5);
        User user = this.getOne(wrapper, false);
        if (user == null) {
            throw new BusinessException("用户名或密码错误");
        } else {
            user.setUpdateTime(new Date());
            UserInfo info = new UserInfo(user);
            String token = tokenService.generateAccessToken(info);
            this.updateById(user);
            return token;
        }
    }

    @Override
    public void logout() {
        tokenService.removeToken(currentLoginUserService.getAccessToken(true));
    }

    @Override
    public IPage<UserVO> page(UserPageSearch search, boolean saveHistory) {

        IPage<User> page = new Page<>(search.getCurrentPage(), search.getPageSize());
        QueryWrapper<User> wrapper = new QueryWrapper<>();
        if (!StringUtils.isEmpty(search.getName())) {
            if (saveHistory) {
                List<String> history = this.listSearch();
                if (!history.contains(search.getName())) {
                    history.add(search.getName());
                    cacheService.set(currentLoginUserService.getUserId(true), history, 7, TimeUnit.DAYS);
                }
            }
            wrapper.lambda().like(User::getName, search.getName());
        }
        if (!StringUtils.isEmpty(search.getAccount())) {
            wrapper.lambda().like(User::getAccount, search.getAccount());
        }

        IPage<UserVO> result = this.page(page, wrapper).convert(UserVO::new);
        if (saveHistory && !CollectionUtils.isEmpty(result.getRecords())) {
            List<String> followedIds = iFollowService.listByFollowerId(currentLoginUserService.getUserId(true));
            result.getRecords().forEach(u -> u.setIsFollowed(followedIds.contains(u.getId())));
        }
        return result;
    }

    @Override
    public void add(UserAddDTO dto) {
        QueryWrapper<User> wrapper = new QueryWrapper<>();
        wrapper.lambda().eq(User::getAccount, dto.getAccount());
        if (this.count(wrapper) > 0) {
            throw new BusinessException("账号已存在");
        }

        User user = new User(dto);
        user.setPassword(DigestUtils.md5DigestAsHex("12345678".getBytes(StandardCharsets.UTF_8)));
        user.setIsAdmin(false);
        this.save(user);
    }

    @Override
    public void update(UserUpdateDTO dto) {
        User user = this.getByIdTx(dto.getId());
        user.setProfileText(dto.getProfileText())
                .setName(dto.getName())
                .setLocation(dto.getLocation())
                .setProfileImg(dto.getProfileImg())
                .setBackgroundImg(dto.getBackgroundImg())
                .setGender(dto.getGender());
        this.updateById(user);

    }

    @Override
    public void reset(String userId) {
        User user = this.getByIdTx(userId);
        user.setPassword(DigestUtils.md5DigestAsHex("12345678".getBytes(StandardCharsets.UTF_8)));
        this.updateById(user);
    }

    @Override
    public void admin(String userId, int type) {
        if (type == 0 && userId.equals(currentLoginUserService.getUserId(true))) {
            throw new BusinessException("不允许取消本人的管理员权限");
        }
        User user = this.getByIdTx(userId);
        user.setIsAdmin(type == 1);
        this.updateById(user);
    }

    @Override
    public List<User> getByIds(List<String> ids) {
        if (CollectionUtils.isEmpty(ids)) {
            return Collections.emptyList();
        } else {
            QueryWrapper<User> wrapper = new QueryWrapper<>();
            wrapper.lambda().in(User::getId, ids);
            return this.list(wrapper);
        }
    }

    @Override
    public List<String> listSearch() {
        String userId = currentLoginUserService.getUserId();
        String temp = cacheService.get(userId, String.class);
        List<String> result = StringUtils.isEmpty(temp) ? new ArrayList<>() : JSON.parseArray(temp, String.class);
        cacheService.set(userId, result, 7, TimeUnit.DAYS);
        return result;
    }

    @Override
    public List<UserVO> listFollow() {
        String userId = currentLoginUserService.getUserId(true);
        List<String> followedIds = iFollowService.listByFollowerId(userId);
        if (CollectionUtils.isEmpty(followedIds)) {
            return Collections.emptyList();
        } else {
            return this.listByIds(followedIds).stream().map(UserVO::new).collect(Collectors.toList());
        }
    }

    @Override
    public UserVO detail(String userId) {
        String curId = currentLoginUserService.getUserId(true);
        userId = StringUtils.isEmpty(userId) ? curId : userId;
        User user = this.getById(userId);
        if (user == null) {
            throw new BusinessException("用户不存在");
        } else {
            UserVO vo = new UserVO(user);
            vo.setIsFollowed(iFollowService.isFollowed(userId, curId))
                    .setFollowNum(iFollowService.countFollow(userId))
                    .setFollowerNum(iFollowService.countFollower(userId))
                    .setLikeCollectNum(iUserNoteService.countLikeCollect(userId));
            return vo;
        }
    }

    @Override
    public void updatePassword(UserPasswordDTO dto) {
        String md5 = DigestUtils.md5DigestAsHex(dto.getOldPassword().getBytes(StandardCharsets.UTF_8));
        String userId = currentLoginUserService.getUserId(true);
        QueryWrapper<User> wrapper = new QueryWrapper<>();
        wrapper.lambda().eq(User::getPassword, md5)
                .eq(User::getId, userId);
        User user = this.getOne(wrapper, false);
        if (user == null) {
            throw new BusinessException("旧密码错误");
        }
        user.setPassword(DigestUtils.md5DigestAsHex(dto.getNewPassword().getBytes(StandardCharsets.UTF_8)));
        this.updateById(user);
    }

    @Override
    public void deleteSearch() {
        String userId = currentLoginUserService.getUserId();
        cacheService.delete(userId);
    }

    @Override
    public void update(UserCurUpdateDTO dto) {
        User user = this.getByIdTx(currentLoginUserService.getUserId(true));
        user.setProfileText(dto.getProfileText())
                .setName(dto.getName())
                .setLocation(dto.getLocation())
                .setProfileImg(dto.getProfileImg())
                .setBackgroundImg(dto.getBackgroundImg())
                .setGender(dto.getGender());
        this.updateById(user);
    }

    @Override
    public void checkAdmin() {
        if (Boolean.FALSE.equals(currentLoginUserService.getUserInfo(true).getIsAdmin())) {
            throw new BusinessException("没有管理员权限");
        }
    }

    @Override
    public List<String> listByNameAndAccount(String name, String account) {
        QueryWrapper<User> wrapper = new QueryWrapper<>();
        wrapper.lambda().select(User::getId);
        if (!StringUtils.isEmpty(name)) {
            wrapper.lambda().like(User::getName, name);
        }
        if (!StringUtils.isEmpty(account)) {
            wrapper.lambda().like(User::getAccount, account);
        }
        return this.list(wrapper).stream().map(User::getId).collect(Collectors.toList());
    }

    private User getByIdTx(String userId) {
        User user = this.getById(userId);
        if (user == null) {
            throw new BusinessException("用户不存在");
        } else {
            return user;
        }
    }
}
